package com.i360day.common.security;

import cn.hutool.core.io.IoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;


public class CreateSecretKey {
    private static Logger logger = LoggerFactory.getLogger(CreateSecretKey.class);

    private final static Security security = new Security();

    public CreateSecretKey() {

    }

    /**
     * <P>@method: sign</p>
     *
     * <p>Title: 签名 <／p>
     *
     * <p>@author z.liju<／p>
     *
     * <p>2018年11月23日 上午11:18:44<／p>
     *
     * <p>return parameter：byte[]  <／p>
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static String sign(String data, String prvateKey) {
        try {
            PrivateKey priK = security.getPrivateKey(prvateKey);
            Signature sig = Signature.getInstance(AbstractKey.SIGNATURE_ALGORITHM);
            sig.initSign(priK);
            sig.update(data.getBytes());
            return Base64Util.encode(sig.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * <P>@method: verify</p>
     *
     * <p>Title: 验证 <／p>
     *
     * <p>@author z.liju<／p>
     *
     * <p>2018年11月23日 上午11:18:50<／p>
     *
     * <p>return parameter：boolean  <／p>
     *
     * @param data
     * @param sign
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static boolean verify(String data, String sign, String publicKeyStr) throws Exception {
        PublicKey publicKey = security.getPublicKey(publicKeyStr);
        Signature sig = Signature.getInstance(AbstractKey.SIGNATURE_ALGORITHM);
        sig.initVerify(publicKey);
        sig.update(data.getBytes());
        return sig.verify(Base64Util.decode(sign));
    }

    /**
     * <P>@method: encrypt</p>
     *
     * <p>Title: 加密 <／p>
     *
     * <p>@author z.liju<／p>
     *
     * <p>2018年11月23日 上午11:19:08<／p>
     *
     * <p>return parameter：String  <／p>
     *
     * @param data
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static String encrypt(String data, String publicKeyStr) throws Exception {
        PublicKey pubKey = security.getPublicKey(publicKeyStr);
        Cipher cipher = Cipher.getInstance(AbstractKey.KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        int inputLen = data.length();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        int i = 0;
        byte[] cache;
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > AbstractKey.MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offSet, AbstractKey.MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * AbstractKey.MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptText = out.toByteArray();
        out.close();
        return AbstractKey.encryptBASE64(encryptText);
    }

    /**
     * <P>@method: decrypt</p>
     *
     * <p>Title: 解密 <／p>
     *
     * <p>@author z.liju<／p>
     *
     * <p>2018年11月23日 上午11:19:18<／p>
     *
     * <p>return parameter：String  <／p>
     *
     * @param data
     * @param privateKeyStr
     * @return
     * @throws Exception
     */
    public static String decrypt(String data, String privateKeyStr) {
        ByteArrayOutputStream out = null;
        try {
            byte[] encryptText = AbstractKey.decryptBASE64(data);
            PrivateKey priKey = security.getPrivateKey(privateKeyStr);
            Cipher cipher = Cipher.getInstance(AbstractKey.KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            int inputLen = encryptText.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > AbstractKey.MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptText, offSet, AbstractKey.MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptText, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * AbstractKey.MAX_DECRYPT_BLOCK;
            }
            byte[] plainText = out.toByteArray();
            return new String(plainText, AbstractKey.ENCODING);
        } catch (Exception e) {
            logger.error("解密出错...{}", e.getMessage());
        } finally {
            IoUtil.close(out);
        }
        return "";
    }

    /**
     * <P>@method: getPublicKey</p>
     *
     * <p>Title: 获取公钥 <／p>
     *
     * <p>@author z.liju<／p>
     *
     * <p>2018年11月23日 上午11:49:25<／p>
     *
     * <p>return parameter：String  <／p>
     *
     * @return
     * @throws Exception
     */
    public static String getPublicKey(String publicKeyStr) throws Exception {
        PublicKey publicKey = security.getPublicKey(publicKeyStr);
        return AbstractKey.encryptBASE64(publicKey.getEncoded());
    }

    /**
     * <P>@method: getPrivateKey</p>
     *
     * <p>Title: 获取私钥 <／p>
     *
     * <p>@author z.liju<／p>
     *
     * <p>2018年11月23日 上午11:49:13<／p>
     *
     * <p>return parameter：String  <／p>
     *
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(String privateKeyStr) throws Exception {
        PrivateKey privateKey = security.getPrivateKey(privateKeyStr);
        return AbstractKey.encryptBASE64(privateKey.getEncoded());
    }



}
